package com.googlecode.imule.redundant;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.DatagramSocket;
import java.net.SocketException;

import com.apple.dnssd.DNSRecord;
import com.apple.dnssd.DNSSD;
import com.apple.dnssd.DNSSDException;
import com.apple.dnssd.DNSSDRegistration;
import com.apple.dnssd.DNSSDService;
import com.apple.dnssd.RegisterListener;
import com.apple.dnssd.TXTRecord;
import com.googlecode.imule.discovery.BrowserAdaptor;
import com.googlecode.imule.discovery.ContactList;

/**
 * A discovery service using Bonjour. The discover service is in control of the 
 * registration and discovery of Bonjour services.
 * 
 * @author Graham Williamson, Neil Cowzer
 */

public class DiscoveryService implements RegisterListener{

	/* The service name and type string. */
	private String serviceRegistrationString;

	/* The name of this application. */
	private String name;

	/* The service browser that searches for new and lost services. */
	private DNSSDService browser;

	/* The object that keeps the register information regarding this service. */
	private DNSSDRegistration register;

	/* The list of available contacts. */
	private ContactList contacts;

	/* The DNSRecord is used. */
	private DNSRecord dnsRecord; 

	/* TEST CODE */
	private ListenerThreads listener;

	/**
	 * Initialise and register a application with a given name if possible. 
	 * 
	 * @param name The preferred name for this client
	 * @throws DNSSDException  if there are complications registering the service
	 */
	public DiscoveryService(String name) throws DNSSDException, SocketException {
		super();

		this.name = name;
		this.serviceRegistrationString = "_imule._udp";

		DatagramSocket inputSocket = new DatagramSocket();	// May need to be changed to merge with Mike's code

		contacts = new ContactList();

		register = DNSSD.register(name, serviceRegistrationString, inputSocket.getPort(), this);
		browser = DNSSD.browse(serviceRegistrationString, new BrowserAdaptor(contacts));

		/* TEST CODE */
		listener = new ListenerThreads(this);
		listener.start();
	}

	/**
	 * Something has gone wrong, the service has failed to register.
	 * 
	 * (Do not call this method directly!)
	 * 
	 * @see com.apple.dnssd.BaseListener#operationFailed(com.apple.dnssd.DNSSDService, int)
	 */
	public void operationFailed(DNSSDService service, int errorCode) {
		System.out.println("Browsing error with service " + service.toString() + ". Error code: " + errorCode);
		System.exit(1);	// close indicating an error occurred
	}

	/**
	 * Called when a service has registered. Upon successful registration 'update' the service's name.
	 * 
	 * (Do not call this method directly!)
	 * 
	 * @see com.apple.dnssd.RegisterListener#serviceRegistered(com.apple.dnssd.DNSSDRegistration, int, java.lang.String, java.lang.String, java.lang.String)
	 */
	public void serviceRegistered(DNSSDRegistration registration, int flags,
			String serviceName, String regType, String domain) {
		// ensure that the name and registered name are the same (clashes force renames)
		name = serviceName;
	}


	/**
	 * Set a text status of the service.
	 * 
	 *	TODO: possibly refactor to use RDF
	 * 
	 * @param status the status of the service
	 */
	public void setStatus(String status){
		TXTRecord record = new TXTRecord();
		record.set("status", status);

		try {
			if (dnsRecord == null)
				dnsRecord = register.getTXTRecord();

			dnsRecord.update(0, record.getRawBytes(), 0);
		} catch (DNSSDException e) {
			System.out.println("update failed");
		}
	}

	/**
	 *	Shutdown the application correctly.
	 */
	public void close(){
		register.stop();	// removes register object for this node
		browser.stop();	// stop searching/browsing the network
		listener.shutdown();	// TEST CODE
	}
}
